package model;

import java.util.ArrayList;

public class Bot extends Player {
	
	private int opponentsNumber = 0;
	private boolean cardsInColor = false;
	private boolean cardsInTrumpColor = false;
	private boolean trumpCardInCalledCards = false;
	private Card bestCardInCalledCards = null;
	private Colors trumpColor = null;
	private ArrayList<Card> calledCards = null;
	private Colors calledColor = null;
	private int sumCardsValue;
	
	public Bot(int playerID,String playerName, int opponentsNumber) {
		super(playerID,playerName);
		this.opponentsNumber = opponentsNumber;
	}
	
	private void testOwnCards() {
		sumCardsValue = 0;
		for(int i = 0; i < cards.size(); ++i) {
			if (cards.get(i).getColor() == trumpColor)
				sumCardsValue += 1.25f*cards.get(i).getValue();
			else
				sumCardsValue += cards.get(i).getValue();
		}
	}
	
	private void testCards() {
		trumpCardInCalledCards = false;
		calledColor = calledCards.get(0).getColor();
		bestCardInCalledCards = calledCards.get(0);
		if (bestCardInCalledCards.getColor() == trumpColor)
			trumpCardInCalledCards = true;
		for(int i = 1; i < calledCards.size(); ++i) {
			if (calledCards.get(i).getColor() == trumpColor) {
				if (trumpCardInCalledCards) {
					if (bestCardInCalledCards.getValue() < calledCards.get(i).getValue())
						bestCardInCalledCards = calledCards.get(i);
				}
				else {
					bestCardInCalledCards = calledCards.get(i);
					trumpCardInCalledCards = true;
				}
			}
			if (calledCards.get(i).getColor() == calledColor && !trumpCardInCalledCards) {
				if (calledCards.get(i).getValue() > bestCardInCalledCards.getValue())
					bestCardInCalledCards = calledCards.get(i);
			}
		}
		
		cardsInColor = false;
		cardsInTrumpColor = false;
		for(int i = 0; i < cards.size(); ++i) {
			if (cards.get(i).getColor() == calledColor)
				cardsInColor = true;
			if (cards.get(i).getColor() == trumpColor)
				cardsInTrumpColor = true;
		}

	}
	
	public Card askForACard(ArrayList<Card> calledCards,
			int thPlayer, Colors trumpColor) {
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		this.calledCards = calledCards;
		this.trumpColor = trumpColor;
		int cardIndex = 0;
		if (thPlayer != 0) {
			testCards();
			testOwnCards();
		}
		
		if ((bid-win > 0) && (sumCardsValue/cards.size()) > ((bid-win) * (10/cards.size())))  {
			if (thPlayer == 0)
				return cards.get(startWithWorstCard());
			else
				return cards.get(worstCard());
		}
			
		
		if (trumpCardInCalledCards && thPlayer != 0) {
			boolean opponentsHaveBetterCard = true;
			if (cardsInTrumpColor) {
				for(int i = 0; i < cards.size(); ++i) {
					if (cards.get(i).getColor() == trumpColor) {
						if (cards.get(i).getValue() > bestCardInCalledCards.getValue()) {
							cardIndex = i;
							opponentsHaveBetterCard = false;
						}
					}
				}
			}
			if (opponentsHaveBetterCard || (bid-win < 0))
				cardIndex = worstCard();
		}
		else if (thPlayer == 0) {
			if (bid-win > 0)
				cardIndex = startWithBestCard();
			else
				cardIndex = startWithWorstCard();
		}
		else if (thPlayer == opponentsNumber) {
			if (bid-win > 0)
				cardIndex = lastCallToWin();
			else
				cardIndex = callToLose();
		}
		else {
			if (bid-win > 0) {
				cardIndex = callToWin();
			}
			else {
				cardIndex = callToLose();
			}
		}
		return cards.get(cardIndex);
	}

	
	private int lastCallToWin() {
		int cardIndex = 0;
		boolean opponentsHaveBetterCard = true;
		for(int i = 1; i < cards.size(); ++i) {
			if (cards.get(i).getColor() == calledColor && cards.get(i).getValue() > bestCardInCalledCards.getValue()) {
				if (cards.get(i).getValue() < cards.get(cardIndex).getValue()) {
					cardIndex = i;
				}
				opponentsHaveBetterCard = false;
			}
		}
		if (opponentsHaveBetterCard && cardsInTrumpColor) {
			cardIndex = 0;
			for(int i = 1; i < cards.size(); ++i)
				if (cards.get(i).getColor() == trumpColor && (cards.get(cardIndex).getColor() != trumpColor))
					cardIndex = i;
				else if (cards.get(i).getValue() < cards.get(cardIndex).getValue() && cards.get(i).getColor() == trumpColor)
					cardIndex = i;
		}
		else
			cardIndex = worstCard();
		return cardIndex;
	}
	
	private int weakestCard() {
		int worstHeartIndex = -1;
		int worstDiamondIndex = -1;
		int worstSpadeIndex = -1;
		int worstClubIndex = -1;
		for(int i = 0; i < cards.size(); ++i) {
			if (cards.get(i).getColor() == Colors.Heart && trumpColor != Colors.Heart) {
				if (worstHeartIndex == -1)
					worstHeartIndex = i;
				else if (cards.get(worstHeartIndex).getValue() > cards.get(i).getValue())
					worstHeartIndex = i;
			}
			else if (cards.get(i).getColor() == Colors.Diamond && trumpColor != Colors.Diamond) {
				if (worstDiamondIndex == -1)
					worstDiamondIndex = i;
				else if (cards.get(worstDiamondIndex).getValue() > cards.get(i).getValue())
					worstDiamondIndex = i;
			}
			else if (cards.get(i).getColor() == Colors.Spade && trumpColor != Colors.Spade) {
				if (worstSpadeIndex == -1)
					worstSpadeIndex = i;
				else if (cards.get(worstSpadeIndex).getValue() > cards.get(i).getValue())
					worstSpadeIndex = i;
			}
			else if (trumpColor != Colors.Club) {
				if (worstClubIndex == -1)
					worstClubIndex = i;
				else if (cards.get(worstClubIndex).getValue() > cards.get(i).getValue())
					worstClubIndex = i;
			}
		}

		int betterCardsInColor[] = new int[4];
		for(int i = 0; i < cards.size(); ++i) {
			if (worstHeartIndex != -1) {
				if (cards.get(i).getColor() == Colors.Heart && cards.get(worstHeartIndex).getValue() < cards.get(i).getValue()) {
					++betterCardsInColor[0];
				}
			}
			if (worstDiamondIndex != -1) {
				if (cards.get(i).getColor() == Colors.Diamond && cards.get(worstDiamondIndex).getValue() < cards.get(i).getValue()) {
					++betterCardsInColor[1];
				}
			}
			if (worstSpadeIndex != -1) {
				if (cards.get(i).getColor() == Colors.Spade && cards.get(worstSpadeIndex).getValue() < cards.get(i).getValue()) {
					++betterCardsInColor[2];
				}
			}
			if (worstClubIndex != -1) {
				if (cards.get(i).getColor() == Colors.Club  && cards.get(worstClubIndex).getValue() < cards.get(i).getValue()) {
					++betterCardsInColor[3];
				}
			}
		}
		
		for(int i = 0; i < allCalledCards.size(); ++i) {
			if (worstHeartIndex != -1) {
				if (allCalledCards.get(i).getColor() == Colors.Heart && cards.get(worstHeartIndex).getValue() < allCalledCards.get(i).getValue()) {
					++betterCardsInColor[0];
				}
			}
			if (worstDiamondIndex != -1) {
				if (allCalledCards.get(i).getColor() == Colors.Diamond && cards.get(worstDiamondIndex).getValue() < allCalledCards.get(i).getValue()) {
					++betterCardsInColor[1];
				}
			}
			if (worstSpadeIndex != -1) {
				if (allCalledCards.get(i).getColor() == Colors.Spade && cards.get(worstSpadeIndex).getValue() < allCalledCards.get(i).getValue()) {
					++betterCardsInColor[2];
				}
			}
			if (worstClubIndex != -1) {
				if (allCalledCards.get(i).getColor() == Colors.Club && cards.get(worstClubIndex).getValue() < allCalledCards.get(i).getValue()) {
					++betterCardsInColor[3];
				}
			}
		}

		int min = 0;
		for(int i = 1; i < 4; ++i) {
			if (betterCardsInColor[min] > betterCardsInColor[i])
				min = i;
		}
		
		int cardIndex = 0;
		if (min == 0 && worstHeartIndex != -1)
			cardIndex = worstHeartIndex;
		else if (min == 1 && worstDiamondIndex != -1)
			cardIndex = worstDiamondIndex;
		else if (min == 2 && worstSpadeIndex != -1)
			cardIndex = worstSpadeIndex;
		else if (min == 3 && worstClubIndex != -1)
			cardIndex = worstClubIndex;
		else {
			for(int i = 1; i < cards.size(); ++i)
				if (cards.get(cardIndex).getValue() > cards.get(i).getValue())
					cardIndex = i;
		}
		
		return cardIndex;
	}
		
	private int worstCard() {
		int cardIndex = 0;
		boolean opponentIsBetter = false;
		if (cardsInTrumpColor && bestCardInCalledCards.getColor() == trumpColor) {
			if (bid-win > 0) {
				opponentIsBetter = false;
			}
			else {
				for(int i = 1; i < cards.size(); ++i) {
					if (cards.get(i).getColor() == trumpColor && cards.get(cardIndex).getColor() != trumpColor
							&& cards.get(i).getValue() < bestCardInCalledCards.getValue()) {
						cardIndex = i;
						opponentIsBetter = true;
					}
					else if (cards.get(cardIndex).getValue() < cards.get(i).getValue() && cards.get(i).getColor() == trumpColor
							&& cards.get(i).getValue() < bestCardInCalledCards.getValue()) {
						cardIndex = i;
						opponentIsBetter = true;
					}
				}
			}
		}
		if (!opponentIsBetter && cardsInColor) {
			cardIndex = 0;
			for(int i = 1; i < cards.size(); ++i) {
				if (cards.get(i).getColor() == calledColor && cards.get(cardIndex).getColor() != calledColor)
					cardIndex = i;
				else if (cards.get(i).getValue() < cards.get(cardIndex).getValue() && cards.get(i).getColor() == calledColor)
					cardIndex = i;
			}
		}
		else if (!opponentIsBetter) {
			cardIndex = 0;
			if (bid-win > 0) {
				cardIndex = weakestCard();
			}
			else {
				for(int i = 1; i < cards.size(); ++i)
					if (cards.get(i).getValue() > cards.get(cardIndex).getValue() && cards.get(i).getColor() != trumpColor)
						cardIndex = i;
			}
		}
		return cardIndex;
	}
	
	private int startWithBestCard() {
		int cardIndex = 0;
		int trumpCardIndex = 0;
		
		for (int i = 1; i < cards.size(); ++i)
			if (cards.get(trumpCardIndex).getColor() != trumpColor && cards.get(i).getColor() == trumpColor)
				trumpCardIndex = i;
			else if (cards.get(trumpCardIndex).getValue() < cards.get(i).getValue() && cards.get(i).getColor() == trumpColor)
				trumpCardIndex = i;
		
		if (cards.get(trumpCardIndex).getColor() != trumpColor)
			return startWithWorstCard();
		
		int numberOfCards = cards.size() * opponentsNumber;
		int temp = 0;
		for (int i = 0; i < allCalledCards.size(); ++i)
			if ((allCalledCards.get(i).getColor() == trumpColor && (allCalledCards.get(i).getValue()) > cards.get(trumpCardIndex).getValue()))
				++temp;
				
		int bound = 0;
		if (numberOfCards <= 20)
			bound = (52-numberOfCards)/8 + 1;
		else
			bound = (52-numberOfCards)/16 + 1;
		
		if ((14 - cards.get(trumpCardIndex).getValue() - temp) < bound)
			cardIndex = trumpCardIndex;
		else if (numberOfCards <= 12) {
			cardIndex = 0;
			for (int i = 1; i < cards.size(); ++i)
				if (cards.get(i).getValue() > cards.get(cardIndex).getValue())
					cardIndex = i;
		}
		else
			return startWithWorstCard();
		return cardIndex;
	}
	
	private int startWithWorstCard() {
		return weakestCard();
	}

	private int callToWin() {
		int cardIndex = 0;
		if (!cardsInColor && !cardsInTrumpColor)
			return worstCard();
		if (cardsInColor) {
			if (cardsInTrumpColor) {
					for(int i = 1; i < cards.size(); ++i) {
						if (cards.get(cardIndex).getColor() != trumpColor && cards.get(i).getColor() == trumpColor)
							cardIndex = i;
						else if (cards.get(i).getColor() == trumpColor && cards.get(i).getValue() > cards.get(cardIndex).getValue())
							cardIndex = i;
					if (bestCardInCalledCards.getColor() == trumpColor
						&& cards.get(cardIndex).getValue() > bestCardInCalledCards.getValue())
						return worstCard();
				}
			}
			else {
				cardIndex = 0;
				for(int i = 1; i < cards.size(); ++i) {
					if (cards.get(i).getColor() == calledColor && (cards.get(cardIndex).getColor() != calledColor))
						cardIndex = i;
					else if (cards.get(i).getValue() > cards.get(cardIndex).getValue() && cards.get(i).getColor() == calledColor)
						cardIndex = i;
				}
				if (cards.get(cardIndex).getValue() < bestCardInCalledCards.getValue())
					return worstCard();
			}
		}
		else if (!cardsInColor && cardsInTrumpColor) {
			cardIndex = 0;
			for(int i = 1; i < cards.size(); ++i) {
				if (cards.get(i).getColor() == trumpColor && (cards.get(cardIndex).getColor() != trumpColor))
					cardIndex = i;
				else if (cards.get(i).getValue() > cards.get(cardIndex).getValue() && cards.get(i).getColor() == trumpColor)
					cardIndex = i;
			}
		}
		return cardIndex;
	}
	
	private int callToLose() {
		int cardIndex = 0;
		boolean opponentIsBetter = false;
		if (cardsInTrumpColor && bestCardInCalledCards.getColor() == trumpColor) {
			for(int i = 1; i < cards.size(); ++i) {
				if (cards.get(i).getColor() == trumpColor && cards.get(cardIndex).getColor() != trumpColor
						&& cards.get(i).getValue() < bestCardInCalledCards.getValue()) {
					cardIndex = i;
					opponentIsBetter = true;
				}
				else if (cards.get(i).getColor() == trumpColor && cards.get(cardIndex).getValue() < cards.get(i).getValue()
						&& cards.get(i).getValue() < bestCardInCalledCards.getValue())
					cardIndex = i;
					opponentIsBetter = true;
			}
		}
		
		if (!opponentIsBetter)
			return worstCard();
		
		return cardIndex;
	}

	public int askForABid(int playersNumber, Colors trumpColor) {
		int weakCards = 0;
		int midCards = 0;
		int strongCards = 0;
		int aceCards = 0;
		int aceTrump = 0;
		int strongTrumps = 0;
		int weakTrumps = 0;
		int midTrumps = 0;
		
		for(int i = 0; i < cards.size(); ++i) {
			if (cards.get(i).getColor() == trumpColor) {
				if (cards.get(i).getValue() < 7) ++weakTrumps;
				else if (cards.get(i).getValue() < 11) ++midTrumps;
				else if (cards.get(i).getValue() < 14) ++strongTrumps;
				else ++aceTrump; 
			}
			else {
				if (cards.get(i).getValue() < 7) ++weakCards;
				else if (cards.get(i).getValue() < 11) ++midCards;
				else if (cards.get(i).getValue() < 14) ++strongCards;
				else ++aceCards;
			}
		}
		float bidFromTrumps = 0;
		float bidFromCards = 0;
		bidFromTrumps += aceTrump;
		bidFromTrumps += (strongTrumps/1.1f)/((opponentsNumber-1)/2.0f);
		bidFromTrumps += (midTrumps/1.4f)/((opponentsNumber-1)/2.0f);
		bidFromTrumps += (weakTrumps/2.0f)/((opponentsNumber-1)/2.0f);
		bidFromCards += (aceCards/1.6f)/((opponentsNumber-1)/2.0f);
		bidFromCards += (strongCards/2.75f)/((opponentsNumber-1)/2.0f);
		bidFromCards += (midCards/5.0f)/((opponentsNumber-1)/2.0f);
		bidFromCards += (weakCards/7.5f)/((opponentsNumber-1)/2.0f);

		int hearts = 0, spades = 0, clubs = 0, diamonds = 0;
		for(int i = 0; i < cards.size(); ++i) {
			if (cards.get(i).getColor() != trumpColor) {
				if (cards.get(i).getColor() == Colors.Heart) ++hearts;
				if (cards.get(i).getColor() == Colors.Spade) ++spades;
				if (cards.get(i).getColor() == Colors.Club) ++clubs;
				if (cards.get(i).getColor() == Colors.Diamond) ++diamonds;
			}
		}
		
		if (cards.size() >= 6) {
			if (hearts > Math.round(0.7f*cards.size()) && trumpColor != Colors.Heart) {
				bidFromCards = 0;
				for(int i = 0; i < cards.size(); ++i) {
					if (cards.get(i).getColor() != Colors.Heart) {
						if (cards.get(i).getValue() < 7)
							bidFromCards += (weakCards/7.5f)/((opponentsNumber-1)/2.0f);
						else if (cards.get(i).getValue() < 11)
							bidFromCards += (midCards/5.0f)/((opponentsNumber-1)/2.0f);
						else if (cards.get(i).getValue() < 14)
							bidFromCards += (strongCards/2.75f)/((opponentsNumber-1)/2.0f);
						else
							bidFromCards += (aceCards/1.6f)/((opponentsNumber-1)/2.0f);
					}
				}
			}
			else if (spades > Math.round(0.7f*cards.size()) && trumpColor != Colors.Spade) {
				bidFromCards = 0;
				for(int i = 0; i < cards.size(); ++i) {
					if (cards.get(i).getColor() != Colors.Spade) {
						if (cards.get(i).getValue() < 7)
							bidFromCards += (weakCards/7.5f)/((opponentsNumber-1)/2.0f);
						else if (cards.get(i).getValue() < 11)
							bidFromCards += (midCards/5.0f)/((opponentsNumber-1)/2.0f);
						else if (cards.get(i).getValue() < 14)
							bidFromCards += (strongCards/2.75f)/((opponentsNumber-1)/2.0f);
						else
							bidFromCards += (aceCards/1.6f)/((opponentsNumber-1)/2.0f);
					}
				}

			}
			else if (diamonds > Math.round(0.7f*cards.size()) && trumpColor != Colors.Diamond) {
				bidFromCards = 0;
				for(int i = 0; i < cards.size(); ++i) {
					if (cards.get(i).getColor() != Colors.Diamond) {
						if (cards.get(i).getValue() < 7)
							bidFromCards += (weakCards/7.5f)/((opponentsNumber-1)/2.0f);
						else if (cards.get(i).getValue() < 11)
							bidFromCards += (midCards/5.0f)/((opponentsNumber-1)/2.0f);
						else if (cards.get(i).getValue() < 14)
							bidFromCards += (strongCards/2.75f)/((opponentsNumber-1)/2.0f);
						else
							bidFromCards += (aceCards/1.6f)/((opponentsNumber-1)/2.0f);
					}
				}

			}
			else if(clubs > Math.round(0.7f*cards.size()) && trumpColor != Colors.Club) {
				bidFromCards = 0;
				for(int i = 0; i < cards.size(); ++i) {
					if (cards.get(i).getColor() != Colors.Club) {
						if (cards.get(i).getValue() < 7)
							bidFromCards += (weakCards/7.5f)/((opponentsNumber-1)/2.0f);
						else if (cards.get(i).getValue() < 11)
							bidFromCards += (midCards/5.0f)/((opponentsNumber-1)/2.0f);
						else if (cards.get(i).getValue() < 14)
							bidFromCards += (strongCards/2.75f)/((opponentsNumber-1)/2.0f);
						else
							bidFromCards += (aceCards/1.6f)/((opponentsNumber-1)/2.0f);
					}
				}

			}
		}
		
		float bid = bidFromTrumps + bidFromCards;
		return Math.round(bid);
	}
}